/***************************************************************************
 *   Copyright (C) 2009 by Bernhard Neuhofer   *
 *   mail@bneu.at   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
using namespace std;

#define TIXML_USE_TICPP
#define TIXML_USE_STL

#include <iterator>
#include <iostream>
#include "ticpp.h"
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <getopt.h>
#include <boost/program_options.hpp>
#include "../tools/log.h"
#include "../AS/CServiceMCP.h"
#include "../tools/mycorba.h"
#include "../SM/CorbaSM.h"
#include "smcontrol.h"

namespace po = boost::program_options;

AddressServer::mcp_var ASmcp;



void createIM ( string messageClass,double timestamp, unsigned int receiver )
{
    FILE_LOG(logINFO)<<"Creating new Message"<<endl;
}
unsigned int debuglevel=0;

//return a reference to the mcp interface on the AS-Server
AddressServer::mcp_var getCServiceMCP(int argc, char** args)
{
    try {
        //Initialize CORBA ORB - "orb"
        CORBA::ORB_var orb=CORBA::ORB_init(argc,args);


        CORBA::Object_var POAObj=orb->resolve_initial_references("RootPOA");
        PortableServer::POA_var _poa=PortableServer::POA::_narrow(POAObj.in());

        CORBA::Object_var nsobj =orb->resolve_initial_references("NameService");

        CosNaming::NamingContext_var initnc =CosNaming::NamingContext::_narrow(nsobj);
        try {

            CosNaming::Name name;

            name.length(2);
            name[0].id = CORBA::string_dup("AddressServer");
            name[0].kind = CORBA::string_dup("");
            name[1].id = CORBA::string_dup("MCP");
            name[1].kind = CORBA::string_dup("");

            cout<<"Resolving mcp object"<<endl;

// Name aufloesen
            CORBA::Object_var obj = initnc->resolve(name);


            cout <<"Found mcp object"<<endl;

// Objektzeiger in Accountzeiger umwandeln
            AddressServer::mcp_var MCP = AddressServer::mcp::_narrow(obj);
            return MCP;


        }
        catch (CosNaming::NamingContext::NotFound & nf)
        {
            FILE_LOG(logERROR)<<"Caught CosNaming::notFoundException."<<endl;
        }
        catch (CosNaming::NamingContext::CannotProceed & nf)
        {
            FILE_LOG(logERROR)<<"Caught CosNaming::CannotProceed."<<endl;
        }
        catch (CosNaming::NamingContext::InvalidName & nf)
        {
            FILE_LOG(logERROR)<<"Caught CosNaming::InvalidName."<<endl;
        }
        catch (CosNaming::NamingContext::AlreadyBound & nf)
        {
            FILE_LOG(logERROR)<<"Caught CosNaming::AlreadyBound."<<endl;
        }
        catch (CosNaming::NamingContext::NotEmpty & nf)
        {
            FILE_LOG(logERROR)<<"Caught CosNaming::NotEmpty."<<endl;
        }

    }
    catch (CORBA::SystemException& se)
    {
        FILE_LOG(logERROR)<<"Caught CORBA::SystemException. "<<endl;
    }
    catch (CORBA::Exception&)
    {
        FILE_LOG(logERROR)<<"Caught CORBA::Exception."<<endl;
    }
    catch (omniORB::fatalException& fe)
    {
        FILE_LOG(logERROR)<<"Caught omniORB::fatalException:"<<endl;
        FILE_LOG(logERROR)<<" file: "<<fe.file()<<endl;
        FILE_LOG(logERROR)<<" line: "<<fe.line()<<endl;
        FILE_LOG(logERROR)<<" mesg: "<<fe.errmsg()<<endl;
    }
    catch (...)
    {
        FILE_LOG(logERROR)<<"Caught unknown exception."<<endl;
    }
    return NULL;
}


int main ( int argc, char** args )

{
    //Parsing command line options

    string configFile="config.xml";
    string nameServer="warp4NameServer";

    po::options_description desc ( "Allowed options" );
    desc.add_options()
    ( "help,h", "produce help message" )
    ( "config,c", po::value< string >(), "set config file" )
    ( "nameserver,n",po::value<string>(),"name of the nameserver" )
    ( "debug,d", po::value< unsigned int >(), "set the debug level [0-3]. Default 0" )
    ;
    po::variables_map vm;
    po::store ( po::parse_command_line ( argc, args, desc ), vm );
    po::notify ( vm );

    if ( vm.count ( "help" ) )
    {
        cout << desc << endl;
        exit ( 0 );
    }

    if ( vm.count ( "config" ) )
    {
        cout << "Config file set to "
             << vm["config"].as<string>() << "."<<endl;
        configFile=vm["config"].as<string>();
    }
    else
        cout << "Config file was no set."<<endl<<"using default:"<<configFile<<endl;

    if ( vm.count ( "nameserver" ) )
    {
        cout <<"Nameserver set to: "<<vm["nameserver"].as<string>() <<"."<<endl;
        nameServer=vm["nameserver"].as<string>();
    }
    else
        cout <<"NameServer was not set"<<endl<<"using default:"<<nameServer<<endl;

    if ( vm.count ( "debug" ) )
    {
        debuglevel=vm["debug"].as<unsigned int>();
        if ( debuglevel>3 ) debuglevel=3;
        cout <<"Setting DebugLevel to: "<<debuglevel<<endl;
        switch ( debuglevel )
        {
        case 0:
            FILELog::ReportingLevel() = FILELog::FromString ( "ERROR" );
            break;
        case 1:
            FILELog::ReportingLevel() = FILELog::FromString ( "WARNING" );
            break;
        case 2:
            FILELog::ReportingLevel() = FILELog::FromString ( "INFO" );
            break;
        case 3:
            FILELog::ReportingLevel() = FILELog::FromString ( "DEBUG" );
            break;
        default:
            FILELog::ReportingLevel() = FILELog::FromString ( "ERROR" );
            break;
        }

    }
    else
    {
        cout <<"Using default DebugLevel: 0 "<<endl;
        FILELog::ReportingLevel() = FILELog::FromString ( "ERROR" );
    }

    //std::cout <<"I am the master control program and I will take over the world"<<std::endl;

    mycorba::instance().init(argc,args);


    //Connect to the AS Server


    ASmcp=getCServiceMCP(argc,args);




    //Start parsing the config file
    try
    {
        ticpp::Document doc ( configFile );
        doc.LoadFile();
        FILE_LOG(logINFO)<<"Loading Config File "<<configFile<<endl;


        ticpp::Node *config_object=doc.FirstChildElement ( "config" );
        ticpp::Node *model_object = config_object->FirstChild ( "model" );

        double endGvt=-1.0;

        //Reading EndGvt
        ticpp::Element *endGvtElement=model_object->FirstChildElement ( "endGvt" );
        endGvtElement->GetText ( &endGvt );
        FILE_LOG(logINFO)<<"EndGvt:"<<endGvt<<endl;
        //Reading SM Definitions
        CORBA::ULong smid;
        string SchedClass;
        try
        {
            ticpp::Iterator<ticpp::Element> sm ( model_object->FirstChildElement ( "SM" ),"SM" );
            while ( sm!=sm.end() )
            {

                smid=0;
                SchedClass="";
                sm->GetAttribute ( "id",&smid );
                sm->GetAttribute ( "schedClass",&SchedClass );
                FILE_LOG(logDEBUG)<<"SM ID:"<<smid<<" SchedClass:"<<SchedClass<<endl;
                SMcontrol* smControl=new SMcontrol(smid,endGvt,SchedClass);
                CORBA::ULong id=0;
                string neighbors,lpClass, meClass,adClass;
                try
                {
                    //Reading LP Defintions of the SM
                    ticpp::Iterator<ticpp::Element> lp ( sm->FirstChildElement ( "LP" ),"LP" );

                    while ( lp!=lp.end() )
                    {
                        id=0;
                        neighbors="";
                        lpClass="";
                        meClass="";
                        adClass="";
                        lp->GetAttribute ( "id",&id );
                        lp->GetAttribute ( "neighbors",&neighbors );

                        stringstream lineStream ( neighbors );
                        vector<unsigned int> vneighbors;
                        unsigned int temp;
                        //parsing neigbors into vector vneighbors
                        while ( lineStream >>temp ) vneighbors.push_back ( temp );

                        lp->GetAttribute ( "lpClass",&lpClass );
                        lp->GetAttribute ( "meClass",&meClass );
                        lp->GetAttribute ( "adClass",&adClass );
                        FILE_LOG(logINFO)<<"-->LP ID:"<<id
                        <<" neighbors:["<<neighbors<<"]"<<"#"<<vneighbors.size()
                        <<" lpClass:"<<
                        lpClass<<" meClass:"<<meClass<<" adClass:"<<adClass
                        <<endl;
                        smControl->addLP(lpClass,meClass,adClass,id,neighbors);

                        lp++;
                    }
                }
                catch ( ticpp::Exception& ex )
                {
                    FILE_LOG(logERROR)<<"Error parsing LP Defintion"<<endl<<"SM:"<<smid<<" LPID:"<<id<<endl<< ex.what();
                    exit ( 0 );
                }
                FILE_LOG(logDEBUG)<<"initSM called";
                smControl->initSM(ASmcp);
                sm++;

            }
        }
        catch ( ticpp::Exception& ex )
        {
            FILE_LOG(logERROR)<<"Error parsing SM Defintion"<<endl<<"SM:"<<smid <<endl<< ex.what();
            exit ( 0 );
        }


        //Reading messages from the config file
        string messageClass;
        double timestamp;
        unsigned int receiver;
        try
        {
            ticpp::Iterator<ticpp::Element> im ( model_object->FirstChildElement ( "IM" ), "IM" );
            while ( im != im.end() )
            {
                messageClass="";
                timestamp=-1.0;
                int receiver=0;
                im->GetAttribute ( "messageClass", &messageClass );
                im->GetAttribute ( "timestamp",&timestamp );
                im->GetAttribute ( "receiver",&receiver );
                FILE_LOG(logDEBUG)<<messageClass<<" "<<timestamp<<" "<<receiver<<endl;
                createIM ( messageClass,timestamp,receiver );
                im++;
            }
        }
        catch ( ticpp::Exception& ex )
        {
            FILE_LOG(logERROR)<<"Error parsing IM Defintion"<<endl
            <<"MessageClass:"<<messageClass
            <<" Timestamp:"<<timestamp
            <<" Receiver:"<<receiver
            <<endl<< ex.what();
            exit ( 0 );
        }

    }
    catch ( ticpp::Exception& ex )
    {
        FILE_LOG(logERROR)<< ex.what();
    }

    return 1;





}
